import json
import yaml
import configparser
from typing import Dict, Any, List, Generator, Optional, Union


class ConfigManager:
    @staticmethod
    def ini_load(filename: str) -> Dict[str, Dict[str, str]]:
        """
        从 INI 格式的配置文件中加载配置项并返回。

        参数：
        - filename: 字符串，要加载的 INI 文件的路径。

        返回值：
        - config_dict: 字典，包含从 INI 文件中加载的配置项。
        """
        config = configparser.ConfigParser()
        config.read(filename, encoding="utf-8")
        config_dict = {}
        for section in config.sections():
            config_dict[section] = dict(config.items(section))
        return config_dict

    @staticmethod
    def ini_dump(data: Dict[str, Dict[str, Any]], filename: str) -> None:
        """
        将配置项写入到 INI 文件中。

        参数：
        - data: 字典，包含要写入到 INI 文件的配置项。格式为 {section: {key: value}}
        - filename: 字符串，要写入的 INI 文件的路径。
        """
        config = configparser.ConfigParser()
        
        for section, options in data.items():
            config[section] = {}
            for key, value in options.items():
                config[section][key] = str(value)
        
        with open(filename, 'w', encoding="utf-8") as configfile:
            config.write(configfile)

    @staticmethod
    def ini_load_string(data: str) -> Dict[str, Dict[str, str]]:
        """
        从 INI 格式的字符串中加载配置项并返回。

        参数：
        - data: 字符串，包含 INI 格式的配置项。

        返回值：
        - config_dict: 字典，包含从 INI 字符串中加载的配置项。
        """
        config = configparser.ConfigParser()
        config.read_string(data)
        config_dict = {}
        for section in config.sections():
            config_dict[section] = dict(config.items(section))
        return config_dict

    @staticmethod
    def ini_dump_string(data: Dict[str, Dict[str, Any]]) -> str:
        """
        将配置项转换为 INI 格式的字符串并返回。

        参数：
        - data: 字典，包含要转换为 INI 字符串的配置项。

        返回值：
        - ini_str: 字符串，包含 INI 格式的配置项。
        """
        config = configparser.ConfigParser()
        
        for section, options in data.items():
            config[section] = {}
            for key, value in options.items():
                config[section][key] = str(value)
        
        # 使用 StringIO 来捕获输出
        from io import StringIO
        output = StringIO()
        config.write(output)
        return output.getvalue()

    @staticmethod
    def json_load(filename: str) -> Dict[str, Any]:
        """
        从 JSON 格式的配置文件中加载配置项并返回。

        参数：
        - filename: 字符串，要加载的 JSON 文件的路径。

        返回值：
        - config_dict: 字典，包含从 JSON 文件中加载的配置项。
        """
        with open(file=filename, mode='r', encoding="utf-8") as file:
            return json.load(fp=file)

    @staticmethod
    def json_loads(data: str) -> Dict[str, Any]:
        """
        从 JSON 格式的字符串中加载配置项并返回。

        参数：
        - data: 字符串，包含 JSON 格式的配置项。

        返回值：
        - config_dict: 字典，包含从 JSON 字符串中加载的配置项。
        """
        return json.loads(s=data)

    @staticmethod
    def json_dump(data: Dict[str, Any], filename: str, ensure_ascii=False) -> None:
        """
        将配置项写入到 JSON 文件中。

        参数：
        - data: 字典，包含要写入到 JSON 文件的配置项。
        - filename: 字符串，要写入的 JSON 文件的路径。
        - ensure_ascii: 布尔值，是否将非 ASCII 字符转为 Unicode 字符。如果包含有中文就选择False。
        """
        with open(file=filename, mode='w', encoding="utf-8") as fileobject:
            json.dump(obj=data, fp=fileobject, indent=4, ensure_ascii=ensure_ascii)

    @staticmethod
    def json_dumps(data: Dict[str, Any], ensure_ascii=False) -> str:
        """
        将配置项转换为 JSON 格式的字符串并返回。

        参数：
        - data: 字典，包含要转换为 JSON 字符串的配置项。
        - ensure_ascii: 布尔值，是否将非 ASCII 字符转为 Unicode 字符。如果包含有中文就选择False。

        返回值：
        - json_str: 字符串，包含 JSON 格式的配置项。
        """
        return json.dumps(data, indent=4, ensure_ascii=ensure_ascii)

    @staticmethod
    def yaml_load(filename: str) -> Dict[str, Any]:
        """
        从 YAML 格式的配置文件中加载配置项并返回。

        参数：
        - filename: 字符串，要加载的 YAML 文件的路径。

        返回值：
        - config_dict: 字典，包含从 YAML 文件中加载的配置项。
        """
        with open(file=filename, mode='r', encoding="utf-8") as fileobject:
            return yaml.load(stream=fileobject, Loader=yaml.Loader)

    @staticmethod
    def yaml_load_all(filename: str) -> Generator[Dict[str, Any], None, None]:
        """
        从 YAML 格式的配置文件中加载多个文档并返回生成器。

        参数：
        - filename: 字符串，要加载的 YAML 文件的路径。

        返回值：
        - generator: 生成器，用于逐个生成从 YAML 文件中加载的配置项。
        """
        with open(file=filename, mode='r', encoding="utf-8") as fileobject:
            return yaml.load_all(stream=fileobject, Loader=yaml.Loader)

    @staticmethod
    def yaml_safe_load(filename: str) -> Dict[str, Any]:
        """
        从 YAML 格式的配置文件中安全加载配置项并返回。

        参数：
        - filename: 字符串，要加载的 YAML 文件的路径。

        返回值：
        - config_dict: 字典，包含从 YAML 文件中加载的配置项。
        """
        with open(file=filename, mode='r', encoding="utf-8") as fileobject:
            return yaml.safe_load(stream=fileobject)

    @staticmethod
    def yaml_safe_load_all(filename: str) -> Generator[Dict[str, Any], None, None]:
        """
        从 YAML 格式的配置文件中安全加载多个文档并返回生成器。

        参数：
        - filename: 字符串，要加载的 YAML 文件的路径。

        返回值：
        - generator: 生成器，用于逐个生成从 YAML 文件中加载的配置项。
        """
        with open(file=filename, mode='r', encoding="utf-8") as fileobject:
            return yaml.safe_load_all(stream=fileobject)

    @staticmethod
    def yaml_dump(data: Dict[str, Any], filename: str, **kwargs) -> None:
        """
        将配置项写入到 YAML 文件中。

        参数：
        - data: 字典，包含要写入到 YAML 文件的配置项。
        - filename: 字符串，要写入的 YAML 文件的路径。
        - **kwargs: 其他传递给 yaml.dump 的参数。
        """
        with open(file=filename, mode='w', encoding="utf-8") as fileobject:
            yaml.dump(data=data, stream=fileobject, **kwargs)

    @staticmethod
    def yaml_dump_all(data: List[Dict[str, Any]], filename: str, **kwargs) -> None:
        """
        将多个配置项写入到 YAML 文件中。

        参数：
        - data: 列表，包含要写入到 YAML 文件的多个配置项。
        - filename: 字符串，要写入的 YAML 文件的路径。
        - **kwargs: 其他传递给 yaml.dump_all 的参数。
        """
        with open(file=filename, mode='w', encoding="utf-8") as fileobject:
            yaml.dump_all(documents=data, stream=fileobject, **kwargs)

    @staticmethod
    def yaml_safe_dump(data: Dict[str, Any], filename: str, **kwargs) -> None:
        """
        将配置项安全地写入到 YAML 文件中。

        参数：
        - data: 字典，包含要写入到 YAML 文件的配置项。
        - filename: 字符串，要写入的 YAML 文件的路径。
        - **kwargs: 其他传递给 yaml.safe_dump 的参数。
        """
        with open(file=filename, mode='w', encoding="utf-8") as fileobject:
            yaml.safe_dump(data=data, stream=fileobject, **kwargs)

    @staticmethod
    def yaml_safe_dump_all(data: List[Dict[str, Any]], filename: str, **kwargs) -> None:
        """
        将多个配置项安全地写入到 YAML 文件中。

        参数：
        - data: 列表，包含要写入到 YAML 文件的多个配置项。
        - filename: 字符串，要写入的 YAML 文件的路径。
        - **kwargs: 其他传递给 yaml.safe_dump_all 的参数。
        """
        with open(file=filename, mode='w', encoding="utf-8") as fileobject:
            yaml.safe_dump_all(documents=data, stream=fileobject, **kwargs)

    @staticmethod
    def detect_format(filename: str) -> Optional[str]:
        """
        检测配置文件的格式。

        参数：
        - filename: 字符串，配置文件的路径。

        返回值：
        - format_str: 字符串，检测到的格式（'ini', 'json', 'yaml', 'yml'），如果无法检测则返回 None。
        """
        if not filename:
            return None
            
        ext = filename.lower().split('.')[-1]
        if ext in ['ini', 'cfg', 'conf']:
            return 'ini'
        elif ext == 'json':
            return 'json'
        elif ext in ['yaml', 'yml']:
            return 'yaml'
        else:
            return None

    @staticmethod
    def auto_load(filename: str) -> Any:
        """
        自动检测文件格式并加载配置。

        参数：
        - filename: 字符串，配置文件的路径。

        返回值：
        - config_data: 配置数据，格式取决于文件类型。
        """
        file_format = ConfigManager.detect_format(filename)
        
        if file_format == 'ini':
            return ConfigManager.ini_load(filename)
        elif file_format == 'json':
            return ConfigManager.json_load(filename)
        elif file_format == 'yaml':
            return ConfigManager.yaml_load(filename)
        else:
            raise ValueError(f"不支持的文件格式: {filename}")


# 使用示例
if __name__ == "__main__":
    # INI 文件操作示例
    ini_data = {
        'section1': {
            'key1': 'value1',
            'key2': 'value2'
        },
        'section2': {
            'key3': 'value3',
            'key4': 'value4'
        }
    }
    
    # 写入 INI 文件
    ConfigManager.ini_dump(ini_data, 'test.ini')
    
    # 读取 INI 文件
    loaded_ini = ConfigManager.ini_load('test.ini')
    print("INI 文件内容:", loaded_ini)
    
    # INI 字符串操作
    ini_string = ConfigManager.ini_dump_string(ini_data)
    print("INI 字符串:")
    print(ini_string)
    
    # 从字符串加载
    parsed_ini = ConfigManager.ini_load_string(ini_string)
    print("从字符串解析的 INI:", parsed_ini)
    
    # 自动检测格式
    format_type = ConfigManager.detect_format('test.ini')
    print(f"检测到的格式: {format_type}")
    
    # 自动加载
    auto_loaded = ConfigManager.auto_load('test.ini')
    print("自动加载的数据:", auto_loaded)
    